package com.bbf.tio.common;

import org.tio.core.ChannelContext;
import org.tio.core.GroupContext;
import org.tio.core.intf.Packet;
import org.tio.server.intf.ServerAioHandler;

import java.nio.ByteBuffer;

/**
 * 消息处理抽象类
 * @author BBF
 */
public abstract class AbstractTioHandler
    implements ServerAioHandler {

  /**
   * 显示接收的数据包
   * @param packet 接收的数据包
   */
  public abstract void showPacket(TioPacket packet);

  /**
   * 编码：把业务消息包编码为可以发送的ByteBuffer
   * 总的消息结构：消息头 + 消息体
   * 消息头结构：4个字节，存储消息体的长度
   * 消息体结构：对象的json串的byte[]
   */
  @Override
  public ByteBuffer encode(Packet packet,
                           GroupContext groupContext,
                           ChannelContext channelContext) {
    TioPacket tioPacket = (TioPacket) packet;
    showPacket(tioPacket);
    byte[] body = tioPacket.getBody();
    int bodyLen = 0;
    if (body != null) {
      bodyLen = body.length;
    }
    //ByteBuffer的总长度是 = 消息头的长度 + 消息体的长度
    int allLen = TioConstants.HEADER_LENGTH + bodyLen;
    //创建一个新的ByteBuffer
    ByteBuffer buffer = ByteBuffer.allocate(allLen);
    //设置字节序
    buffer.order(groupContext.getByteOrder());
    //写入消息头----消息头的内容就是消息体的长度
    buffer.putInt(allLen);
    //写入消息体
    if (body != null) {
      buffer.put(body);
    }
    return buffer;
  }

  /**
   * 解码：把接收到的ByteBuffer，解码成应用可以识别的业务消息包
   * 总的消息结构：消息头 + 消息体
   * 消息头结构：4个字节，存储消息体的长度
   * 消息体结构：对象的json串的byte[]
   */
  @Override
  public TioPacket decode(ByteBuffer buffer,
                          ChannelContext channelContext) {
    int readableLength = buffer.limit() - buffer.position();
    //为兼容其他socket发送，接收端不要实现 head 4字节，可以参考test/TioClientHandler.java -> decode
    // 不够消息体长度(剩下的buffer组不了消息体)
    if (readableLength < 0) {
      return null;
    } else {
      //组包成功
      TioPacket imPacket = new TioPacket();
      if (readableLength > 0) {
        byte[] dst = new byte[readableLength];
        buffer.get(dst);
        imPacket.setBody(dst);
      }
      return imPacket;
    }
  }
}
